package com.yzi.core.json
{
	import flash.utils.describeType;

	public class JSONEncoder
	{
		private var m_jsonString:String;
		
		public function JSONEncoder($value:*)
		{
			m_jsonString = convertToString($value);
		}
		
		private function convertToString($value:*): String
		{
			var result:String = "";
			
			if($value is String) {
				result = escapeString($value as String);
			} else if($value is Number) {
				result = isFinite($value as Number) ? $value.toString() : "null";				
			} else if($value is Boolean) {
				result = $value ? "true" : "false";
			} else if($value is Array) {
				result = arrayToString($value as Array);
			} else if($value is Object && $value != null) {
				result = objectToString($value);
			}
			
			return result;
		}
		
		private function escapeString($string:String): String
		{
			var result:String = "";
			var char:String;
			
			for(var i:int = 0; i < $string.length; ++i)
			{
				char = $string.charAt( i );
				switch(char) {
					case '"':	// quotation mark
						result += "\\\"";
						break;
					case '\\':	// reverse solidus
						result += "\\\\";
						break;
					case '\b':	// bell
						result += "\\b";
						break;
					case '\f':	// form feed
						result += "\\f";
						break;
					case '\n':	// newline
						result += "\\n";
						break;
					case '\r':	// carriage return
						result += "\\r";
						break;
					case '\t':	// horizontal tab
						result += "\\t";
						break;
					default:
						if (char < ' ') {
							var hexCode:String = char.charCodeAt( 0 ).toString( 16 );
							var zeroPad:String = hexCode.length == 2 ? "00" : "000";
							result += "\\u" + zeroPad + hexCode;
						} else {
							result += char;
						}
						break;
				}
			}
			result = "\"" + result + "\"";
			
			return result;
		}
		
		private function arrayToString($array:Array): String
		{
			var result:String = "";
			
			for(var i:int = 0; i < $array.length; ++i)
			{
				if(result.length > 0) result += ",";
				
				result += convertToString($array[i]);
			}
			result = "[" + result + "]";
			
			return result;
		}
		
		private function objectToString($object:Object): String
		{
			var result:String = "";
			var classInfo:XML = describeType($object);
			
			if(classInfo.@name.toString() == "Object") {
				var value:Object;
				
				for each(var key:String in $object)
				{
					value = $object[key];
					
					if(value is Function) continue;
					
					if(result.length > 0) result += ","
					
					result += escapeString( key ) + ":" + convertToString( value );
				}
			} else {
				for each(var variable:XML in classInfo..*.(name() == "variable" || name() == "accessor"))
				{
					if(result.length > 0) result += ","
					
					result += escapeString(variable.@name.toString()) + ":" + convertToString($object[variable.@name]);
				}
			}
			result = "{" + result + "}"; 
			
			return result;
		}
		
		public function GetString(): String { return m_jsonString; }
	}
}